﻿#region License
/* **********************************************************************************
 * Copyright (c) Haugen Applications LLC
 * This source code is subject to terms and conditions of the MIT License
 * for UserScript. A copy of the license can be found on the License tab for this CodePlex release
 * By using this source code in any fashion, you are agreeing to be bound by the terms of the 
 * MIT License.
 * You must not remove this notice from this software.
 * **********************************************************************************/
#endregion

using UserScript.ExpressionParsing.Irony.Parsing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace UserScript.ExpressionParsing
{
    internal class ExpressionGrammar : Irony.Parsing.Grammar
    {
        internal ExpressionGrammar()
            : base(false)
        { //SQL is case insensitive
            //Terminals
            var number = new NumberLiteral("number");
            var stringLiteral = TerminalFactory.CreateCSharpString("string");
            var idSimple = TerminalFactory.CreateCSharpIdentifier("id_simple");
            var comma = ToTerm(",");
            var NULL = ToTerm("NULL");

            //Non-terminals
            var expression = new NonTerminal("expression");
            var term = new NonTerminal("term");
            var binExpr = new NonTerminal("binExpr");
            var binOp = new NonTerminal("binOp");
            var funCall = new NonTerminal("funCall");
            var funArgs = new NonTerminal("funArgs");
            var unExpr = new NonTerminal("unExpr");
            var unOp = new NonTerminal("unOp");

            //BNF Rules
            this.Root = expression;
            
            //Expression
            expression.Rule = term | binExpr | unExpr;
            term.Rule = stringLiteral | idSimple | number | funCall | NULL;
            binExpr.Rule = expression + binOp + expression;
            binOp.Rule = ToTerm("+") | "-" | "*" | "/" | "%" //arithmetic
                       | "=" | ">" | "<" | ">=" | "<=" | "<>" | "!="
                       | "&&" | "||";

            unExpr.Rule = unOp + expression;
            unOp.Rule = ToTerm("!") | "-";

            funCall.Rule = idSimple + "(" + funArgs + ")";
            funArgs.Rule = MakePlusRule(funArgs, comma, expression);

            //Operators
            RegisterOperators(10, "*", "/", "%");
            RegisterOperators(9, "+", "-");
            RegisterOperators(8, "=", "!=", ">", "<", ">=", "<=");
            RegisterOperators(7, "&&");
            RegisterOperators(6, "||");

            this.AddTermsReportGroup("constant", number, stringLiteral);

            MarkPunctuation(",", "(", ")");
            // Transient non-terminals cannot have more than one non-punctuation child nodes.
            base.MarkTransient(term,  expression);
            binOp.SetFlag(TermFlags.InheritPrecedence);

        }//constructor
    }
}